package org.flyan.ffsm.core.state;

import org.flyan.ffsm.core.event.Event;
import org.flyan.ffsm.core.arg.Args;
import org.flyan.ffsm.core.sm.StateMachine;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 基础状态
 * <p>
 * 表示状态机中的一个当前状态
 * <p>
 * 一个状态必须给定一个能表示该状态的标志，该标志建议使用枚举类，当然，
 * 如若喜欢，自己编写统一的状态标志类来表示也是极为不错的，若这样，该类
 * 必须实现 hashCode() 方法。
 *
 * @param <ST> 状态标志
 * @param <ET> 事件标志
 * @author flyan
 * @version 1.0.0
 * @date 6/23/22
 * @since 1.0.0
 */
public class State<ST, ET>
        implements Serializable {

    private static final long serialVersionUID = -6730601778444181372L;

    /**
     * 状态标志
     */
    private final ST stateTag;

    /**
     * 当前状态上的事件表
     */
    private final Map<ET, Event<ST, ET>> eventTable = new HashMap<>();

    /**
     * 状态所在的状态机
     */
    private StateMachine<ST, ET> stateMachine;

    /**
     * 注册一个事件
     *
     * @param event 事件
     */
    public void registerEvent(Event<ST, ET> event) {
        eventTable.put(event.getEventTag(), event);
        event.bindState(this);
    }

    public void bindStateMachine(StateMachine<ST, ET> stateMachine) {
        if(this.stateMachine == null) {
            this.stateMachine = stateMachine;
        }
    }

    public StateMachine<ST, ET> getStateMachine() {
        return stateMachine;
    }

    /**
     * 检查一个事件是否存在于当前状态
     *
     * @param eventTag 事件标志
     * @return
     */
    public boolean eventExists(ET eventTag) {
        return eventTable.containsKey(eventTag);
    }

    public Event<ST, ET> findEvent(ET eventTag) {
        if(eventExists(eventTag)) {
            try {
                return eventTable.get(eventTag).clone().setCurrState(this);
            } catch (CloneNotSupportedException ignored) {
            }
        }
        return null;
    }

    /**
     * 事件发生
     *
     * @param eventTag 发生的事件标志
     * @return 发生事件后新的状态
     */
    public State<ST, ET> eventHappen(ET eventTag, Args args) {
        /* 事件存在，事件发生，产生动作 */
        if (eventExists(eventTag)) {
            try {
                return eventTable.get(eventTag)
                        .clone()
                        .setCurrState(this)
                        .act(args);
            } catch (CloneNotSupportedException ignored) {
                /* 我们保证 Event 是实现 Cloneable 的 */
            }
        }
        /* 事件不存在于当前状态，不可达状态 */
        return null;
    }

    public State(ST stateTag) {
        this.stateTag = stateTag;
    }

    public ST getStateTag() {
        return stateTag;
    }

    public List<Event<ST, ET>> getEventTable() {
        return eventTable.values().stream().map(event -> {
            try {
                return event.clone().setCurrState(this);
            } catch (CloneNotSupportedException ignored) {
            }
            return null;
        }).filter(Objects::nonNull).collect(Collectors.toList());
    }

    /**
     * 获取当前状态是不是一个最终状态，最终状态不会有任何事件，意味着不会有任何途径转换为其他状态。
     * 例如输入密码成功与否就是两个最终态。
     *
     * @return
     */
    public boolean isFinal() {
        return eventTable.isEmpty();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        State<?, ?> state = (State<?, ?>) o;
        return stateTag.equals(state.stateTag);
    }

    @Override
    public int hashCode() {
        return stateTag.hashCode();
    }

    @Override
    public String toString() {
        return "State{" +
                "stateTag=" + stateTag +
                ", finalState: " + isFinal() +
                ", eventTable=" + eventTable +
                '}';
    }
}